#include "bezier_surface.h"
#include <iostream>
#include <cmath>

BezierSurface::BezierSurface(int _n, double _d) : sizeControl(_n), discretization(_d){
    controlPoints = new Point**[sizeControl];

	for(int i = 0 ; i < sizeControl; i++)
		controlPoints[i] = new Point*[sizeControl];


    //TODO entender pq não da 10
    sizePoints = (int)(1.0/discretization) + 2;
    points = new Point*[sizePoints];
	for(int i = 0 ; i < sizePoints; i++)
		points[i] = new Point[sizePoints];

}

BezierSurface::~BezierSurface(){
	for(int i = 0; i < sizeControl; i++){
        for(int j = 0; j < sizeControl; j++){
            delete controlPoints[i][j];
        }
        delete[] controlPoints[i];
	}
	delete[] controlPoints;

	for (int i = 0; i < sizePoints; i++)
		delete [] points[i];
	delete [] points;
}

void BezierSurface::addBezierPoint(int _i, int _j, Point *_p){
    controlPoints[_i][_j] = _p;
}

Point *BezierSurface::getControlPoint(int _i, int _j){
    return controlPoints[_i][_j];
}

Point BezierSurface::getPoint(int _i, int _j){
    return points[_i][_j];
}

int BezierSurface::getSizePoints(){
    return sizePoints;
}

int BezierSurface::getSizeControl(){
    return sizeControl;
}

double BezierSurface::getDiscretization(){
    return discretization;
}

int BezierSurface::binomial(int _i, int _n){
    int iFat = 1, nFat = 1, inFat = 1;

    if(_i < _n){
        //trocando i e n
        double temp = _i;
        _i = _n;
        _n = temp;
    }
    if (_n < (_i-_n)){
        //trocando n e i -n
        _n = _i - _n;
    }
//_i sempre sera o maior
    if(!((_i - _n) == 1 || (_i - _n) == 0)){
        for(int j = (_i - _n); j > 1; j--)
            inFat *= j;
    }

    if(!(_n == 1 || _n == 0)){
        for(int j = _n; j > (_i - _n); j--)
            nFat *= j;
        nFat *= inFat;
    }

    if(!(_i == 1 || _i == 0)){
        for(int j = _i; j > _n; j--)
            iFat *= j;
        iFat *= nFat;
    }
    return (iFat / (nFat * inFat));
}

void BezierSurface::calculate(){
    double q;
    Point p;

    for(int u = 0; u < sizePoints; u++){
        for(int v = 0; v < sizePoints; v++){
            p = Point(0.0, 0.0, 0.0);

            for (int i = 0; i < sizeControl; i++){
                for (int j = 0; j < sizeControl; j++){
                    q = binomial(i, sizeControl-1) * pow(u * discretization, i) * pow(1.0 - (u * discretization), sizeControl-1 - i) * binomial(j, sizeControl-1) * pow(v * discretization, j) * pow(1.0 - (v * discretization), sizeControl-1 - j);
                    p = p + ((*controlPoints[i][j]) * q);
                }
            }
            points[u][v] = p;
        }
    }

}

void BezierSurface::translate(Point _p){
}
